/**
 * ESUtil覆盖原生方法工具
 * @type notype
 */
export default class util {
    /**
     * 获取class下面所有方法，默认是获取静态方法，如果要获取对象方法，传入_obj.prototype
     * @param _obj
     * @returns
     */
    static getClassNames(_obj: any) {
        const KNOWN_STATICS: any = {
            name: true,
            length: true,
            prototype: true,
            caller: true,
            callee: true,
            arguments: true,
            arity: true,
            constructor: true
        }
        let result = []
        let keys = Object.getOwnPropertyNames(_obj)
        for (let i = 0; i < keys.length; ++i) {
            const key = keys[i]
            if (!KNOWN_STATICS[key] && typeof _obj[key] === 'function') {
                result.push(key)
            }
        }
        return result
    }

    /**
     * 将传入的方法统一转为function xxx(){}格式
     * @param fun
     * @returns
     */
    private static getFunction = (fun: Function) => {
        const funName = fun.name
        const funstr = fun + ''
        const startIndex = funstr.indexOf('{')
        const isYield = funstr.substring(0, startIndex).indexOf('*') != -1 ? '*' : ''
        if (funstr.substring(0, startIndex).indexOf('=>') != -1) {
            //用于处理存在箭头函数时
            return new Function(
                `return function${isYield} ${funName} ${
                    funstr.substring(0, funstr.indexOf(')') + 1) + funstr.substring(startIndex)
                }`
            )()
        }
        return new Function(`return function${isYield} ${funName}${funstr.substring(funstr.indexOf('('))}`)()
    }

    /**
     * 定义默认属性
     * @param obj 如Array,Object,Function,Map,Set,Date等
     * @param funName 函数名称 如:sum
     * @param fun 如:function (){return 0}、()=>{return 0}
     * @example
    ESUtil.setPrototype(Array,"sum",function () {
        //@ts-ignore
        const _this: Array<any> = this
        return "累加"
    })
     */
    static setPrototype = (obj: any, funName: any, fun: Function) => {
        fun = util.getFunction(fun)
        Object.defineProperty(obj.prototype, funName, {
            writable: true,
            enumerable: false,
            value: fun
        })
    }

    /**
     * 将自定义类覆盖到属性中
     * @param classObj
     * @param proName 如Array,Map等
     */
    static classSetToProperty = (classObj: any, proName: string) => {
        const staticArr = util.getClassNames(classObj)
        staticArr.forEach((funStr) => {
            util.setPrototype(window[proName], funStr, classObj[funStr])
        })
    }

    static iterator = function () {
        let _this = this
        let keys = Object.keys(_this)
        let i = 0
        if (this._Vue3ToolIterator === '_Vue3ToolIterator') {
            keys = this.keys
            _this = this.obj
        }

        return new (class ObjectIterator {
            _Vue3ToolIterator = '_Vue3ToolIterator'
            obj = _this
            keys = keys
            next = () => {
                i++
                return {
                    value: i > keys.length ? null : _this[keys[i - 1]],
                    done: i > this.keys.length
                }
            }

            constructor() {
                return this
            }
        })()
    }
}
